package com.cx.base.day19_thread;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * @Author: robert.song
 * @Date: Created in 2021/11/26
 * LongAdder类是Doug Lea的作品，设计精巧
 * LongAdder主要有几个关键域
 * 累加单元数组，懒惰初始化
 * transient volatile Cell[] cells;
 * 基础值，如果没有竞争，则用cas累加这个域
 * transient volatile Long base;
 * 在cells创建或者扩容时，置为1，表示加锁
 * transient volatile int cellsBusy
 */
@Slf4j(topic = "c.Test")
public class Thread_13_8_原子性_LongAdder {

    public static void main(String[] args) {
        demo(() -> new LongAdder(), (longAdder) -> longAdder.add(1l));
    }

    /**
     * @param adderSupplier 提供累加器对象
     * @param action        执行累加器指令
     * @param <T>
     */
    private static <T> void demo(Supplier<T> adderSupplier, Consumer<T> action) {
        T adder = adderSupplier.get();
        List<Thread> ts = new ArrayList<>();
//        四个线程，每个累加50万
        for (int i = 0; i < 4; i++) {
            ts.add(new Thread(() -> {
                long start = System.nanoTime();
                for (int j = 0; j < 500000; j++) {
                    action.accept(adder);
                }
                long end = System.nanoTime();
                System.out.println(Thread.currentThread() + "：" + ((end - start) / 1000000));
            }));
        }

        try {
            ts.forEach(t -> t.start());
            Thread.sleep(20000);
            System.out.println(Thread.currentThread() + "：" + adder);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

@Slf4j(topic = "c.Test")
class LockCas {
    //        0 表示没有加锁，1表示加锁
    private AtomicInteger state = new AtomicInteger(0);

    public void lock() {
        while (true) {
            if (state.compareAndSet(0, 1)) {
                break;
            }
        }
    }

    public void unlock() {
        log.info("unlock...");
        state.set(0);
    }

    public void test() {
        LockCas lockCas = new LockCas();
        new Thread(() -> {
            log.info("begin...");
            lockCas.lock();
            try {
                log.info("lock...");
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lockCas.unlock();
            }
        }, "t1").start();
        new Thread(() -> {
            log.info("begin...");
            lockCas.lock();
            try {
                log.info("lock...");
            } finally {
                lockCas.unlock();
            }
        }, "t2").start();
    }
}